package com.gyt.manager.common.utils;

import com.aspose.words.Document;
import com.aspose.words.License;
import com.aspose.words.SaveFormat;
import com.lowagie.text.DocumentException;
import com.lowagie.text.pdf.BaseFont;
import freemarker.template.Configuration;
import freemarker.template.DefaultObjectWrapper;
import freemarker.template.Template;
import freemarker.template.TemplateException;
import freemarker.template.TemplateExceptionHandler;
import freemarker.template.Version;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.ui.freemarker.FreeMarkerTemplateUtils;
import org.thymeleaf.util.MapUtils;
import org.xhtmlrenderer.pdf.ITextFontResolver;
import org.xhtmlrenderer.pdf.ITextRenderer;
import sun.misc.BASE64Encoder;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import java.io.BufferedWriter;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.StringWriter;
import java.io.Writer;
import java.util.Locale;
import java.util.Map;

/**
 * description.
 *
 * @author gyt create on 2021/5/10 10:34
 */
public class FreeMarkerUtil {

    private static final Logger LOGGER =
            LoggerFactory.getLogger(FreeMarkerUtil.class);
    private static final String ENCODING = "UTF-8";

    private static final Configuration CFG = new Configuration(new Version("2.3.23"));

    private static final String LICENSE_PATH = "/config/templates/license.xml";
    private static final String PATH = "/config/templates";
    //初始化
    static {
        //1.设置模板所在文件夹
        CFG.setClassForTemplateLoading(FreeMarkerUtil.class, PATH);
        //2.设置国家及其编码，避免ftl文档中的中文在生成html时出现乱码
        CFG.setEncoding(Locale.getDefault(), ENCODING);
        //3.设置对象的包装器
        CFG.setObjectWrapper(new DefaultObjectWrapper(new Version("2.3.23")));
        //4.设置异常处理器,${a.b.c.d}即使没有属性也不会出错
        CFG.setTemplateExceptionHandler(TemplateExceptionHandler.IGNORE_HANDLER);
    }

    /**
     * 获取目标文件的模板
     * @param targetFileName
     * @return
     */
    public static Template getTemplate(String targetFileName) throws IOException {
        return CFG.getTemplate(targetFileName, ENCODING);
    }

    /**
     * 生成模板字符串
     * @param templateName
     * @param param
     * @return
     */
    public static String templateToString(String templateName, Map<String, Object> param){
        if (MapUtils.isEmpty(param)) {
            return StringUtils.EMPTY;
        }
        try {
            Template template = getTemplate(templateName);
            return FreeMarkerTemplateUtils.processTemplateIntoString(template, param);
        } catch (Exception e) {
            LOGGER.error("parse template error-->", e);
        }
        return StringUtils.EMPTY;

    }

    /**
     * 获取图片的base64码
     * @param src
     * @return
     * @throws IOException
     */
    public static String getImageBase(String src) throws IOException {
        if (StringUtils.isBlank(src)) {
            return StringUtils.EMPTY;
        }
        File file = new File(src);
        if (!file.exists()) {
            return StringUtils.EMPTY;
        }
        FileInputStream inputStream = new FileInputStream(file);
        byte[] data = new byte[inputStream.available()];
        inputStream.read(data);
        inputStream.close();

        BASE64Encoder encoder = new BASE64Encoder();
        return encoder.encode(data);
    }

    /**
     * 生成word文档
     * 根据原始word文档，转对应的xml文档，再制作对应ftl
     * @param data
     * @param inputFileName
     * @param outFileName
     * @return
     */
    public static File getDocFile(Map<String, Object> data, String inputFileName, String outFileName){

        Writer out = null;
        File outFile = new File(outFileName);
        try {
            Template template = getTemplate(inputFileName);
            out = new OutputStreamWriter(new FileOutputStream(outFile), ENCODING);
            //处理模板
            template.process(data, out);
        } catch (IOException e) {
            LOGGER.error("get templates file fail->", e);
        } catch (TemplateException e) {
            LOGGER.error("generate result file fail->", e);
        } finally {
            try {
                if (out != null){
                    out.close();
                }
            } catch (IOException e) {
                LOGGER.error("closed write stream fail->", e);
            }
        }
        return outFile;
    }

    /**
     * 设置license
     * @return
     */
    public static boolean getLicense(){
        boolean result = false;
        //InputStream inputStream = DocUtil.class.getClassLoader().getResourceAsStream("/config/templates/license.xml");
        Resource resource = new ClassPathResource(LICENSE_PATH);
        License license = new License();
        try {
            license.setLicense(resource.getInputStream());
            result = true;
        } catch (Exception e) {
            LOGGER.error("set license error:{}", e.getMessage(), e);
        }
        return result;
    }

    /**
     * word转pdf
     * @param inFileName
     * @param outFileName
     * @return
     */
    public static File doc2pdf(String inFileName, String outFileName){
        boolean license = getLicense();
        if (!license){
            LOGGER.info("get license fail");
        }
        //新建空白pdf文档
        File outFile = new File(outFileName);
        FileOutputStream outputStream = null;
        try {
            outputStream = new FileOutputStream(outFile);
            Document document = new Document(inFileName);
            // 全面支持DOC, DOCX, OOXML, RTF HTML, OpenDocument, PDF, EPUB, XPS, SWF 相互转换
            document.save(outputStream, SaveFormat.PDF);
        } catch (Exception e) {
            LOGGER.error("templates file transfer fail:{}", e.getMessage(), e);
        } finally {
            if (outputStream != null){
                try {
                    outputStream.flush();
                    outputStream.close();
                } catch (IOException e) {
                    LOGGER.error("closed outputStream exception:{}", e.getMessage(), e);
                }
            }
        }
        return outFile;
    }

    /**
     *  生成pdf文档
     *  1.根据word文档，制作对应的html文档
     *  2.由于xhtmlrenderer对格式要求较高，必须标准的html,否则报错
     *  3.再由html-ftl即可
     * @param data
     * @param inputFileName
     * @param outFileName
     * @return
     */
    public static File getPdfFile(Map<String, Object> data, String inputFileName, String outFileName) throws DocumentException {

        File outFile = new File(outFileName);
        FileOutputStream outputStream = null;
        BufferedWriter writer = null;
        try {
            StringWriter stringWriter = new StringWriter();
            writer = new BufferedWriter(stringWriter);
            Template template = getTemplate(inputFileName);
            template.process(data, writer);
            DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
            ByteArrayInputStream arrayInputStream = new ByteArrayInputStream(stringWriter.toString().getBytes(ENCODING));
            org.w3c.dom.Document document = builder.parse(arrayInputStream);

            //中文支持
            ITextRenderer renderer = new ITextRenderer();
            ITextFontResolver fontResolver = renderer.getFontResolver();
            fontResolver.addFont("/config/pdf/arialuni.ttf", BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);
            fontResolver.addFont("/config/pdf/simsun.ttc", BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);
            fontResolver.addFont("/config/pdf/MSYH.TTF", BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);

            renderer.setDocument(document, null);
            renderer.layout();
            outputStream = new FileOutputStream(outFile);
            renderer.createPDF(outputStream);
            outputStream.flush();
        } catch (Exception e) {
            LOGGER.error("create pdf exception->", e);
        } finally {
            try {
                if (outputStream != null) {
                    outputStream.close();
                }
                if (writer != null) {
                    writer.close();
                }
            } catch (Exception e) {
                LOGGER.error("closed stream exception->",e);
            }
        }
        return outFile;
    }
}
